Skip to content

wasi-http: validate the Host header used as incoming request authority - #15023

Open
netliomax25-code wants to merge 1 commit into
bytecodealliance:mainfrom
netliomax25-code:wasi-http-incoming-host-authority
Open

netliomax25-code wants to merge 1 commit into
bytecodealliance:mainfrom
netliomax25-code:wasi-http-incoming-host-authority

Conversation

@netliomax25-code

Copy link
Copy Markdown
Contributor

When an incoming request's target has no authority (the usual origin-form GET /path), incoming-request.authority falls back to the Host header. The p2 path in new_incoming_request copied that header string verbatim, so a client can hand the guest an "authority" that is not one at all. With wasmtime serve and a p2 proxy component, these Host values all come through unchanged today:

Host: evil.com#.example.com    -> authority "evil.com#.example.com"
Host: evil.com/x?.example.com  -> authority "evil.com/x?.example.com"
Host: user@evil.com            -> authority "user@evil.com"
Host: example.com:abc          -> authority "example.com:abc"
Host: a b                      -> authority "a b"

A guest that checks the authority with something like ends_with(".example.com") and then builds http://{authority}/... for a redirect or an absolute link ends up pointing at evil.com. The p3 path in Prepared::new already parses the header with http::uri::Authority, which rejects the first three of these but still accepts userinfo and a non-numeric port.

Both incoming paths now use the crate's existing parse_authority, which already enforces the uri-host [":" port] grammar for outgoing authorities. For p2 an invalid Host gets a 400, as RFC 9112 section 3.2 requires and as p2 already does for a missing Host. p3 keeps its current behavior of leaving the authority unset when the header doesn't parse. Requests whose target carries an authority are unchanged.

I added a unit test next to set_status_code_range that checks valid hosts (including [::1]:443) still come through and the values above get a 400. It fails without the fix and passes with it. cargo test -p wasmtime-wasi-http (unit, integration and doc tests), cargo clippy -p wasmtime-wasi-http --all-targets and cargo fmt --all -- --check all pass locally.

@netliomax25-code
netliomax25-code requested a review from a team as a code owner October 27, 2026 07:01
@netliomax25-code
netliomax25-code requested review from rvolosatovs and removed request for a team October 27, 2026 07:01

@rvolosatovs rvolosatovs left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

generally, values passed by the embedder to wasi-http are assumed to be valid (e.g. we don't validate Content-Length of a body originating from the host)

Following this approach, I'd expect wasmtime serve to perform this validation before passing the incoming request to e.g. new_incoming_request.

All that said, it is a fairly small change and a quick check, and performing this validation on construction, at least as a safeguard, seems harmless so LGTM

@rvolosatovs
rvolosatovs added this pull request to the merge queue Oct 27, 2026
@pchickey
pchickey removed this pull request from the merge queue due to a manual request Oct 27, 2026

@pchickey pchickey left a comment •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There's a comprehensive set of changes and tests for this in #14988 - lets stick with that PR, which is nearly complete

@xia-chao

Copy link
Copy Markdown
Contributor

Thank you! #14988 is already covered

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants